JWT (JSON Web Token) একটি স্ট্যান্ডার্ড টোকেন-ভিত্তিক অথেনটিকেশন মেকানিজম। এটি সাধারণত Stateless Authentication এর জন্য ব্যবহৃত হয়। Spring Security-তে JWT Authentication কনফিগার করলে, সেশন ব্যবস্থাপনা ছাড়াই ব্যবহারকারীর তথ্য যাচাই করা যায়।
JWT Authentication-এর কাজের ধাপ:
- User Login:
- ব্যবহারকারী লগইন করে এবং তার credentials পাঠায়।
- সার্ভার credentials যাচাই করে একটি JWT Token জেনারেট করে।
- JWT Token Validation:
- প্রতিটি রিকোয়েস্টের সাথে টোকেন পাঠানো হয় (সাধারণত Authorization Header এর মাধ্যমে)।
- Spring Security টোকেন যাচাই করে ব্যবহারকারীর পরিচয় নিশ্চিত করে।
- Access to Resources:
- টোকেন যাচাই সফল হলে ব্যবহারকারী নির্দিষ্ট রিসোর্সে অ্যাক্সেস পায়।
Spring Security-তে JWT Authentication কনফিগারেশন
Step 1: প্রয়োজনীয় ডিপেন্ডেন্সি যোগ করা
Maven Dependency:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
Step 2: JWT Utility Class তৈরি করা
JWT Token জেনারেট এবং যাচাই করার জন্য একটি Utility Class:
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
import org.springframework.stereotype.Component;
@Component
public class JwtUtil {
private final String SECRET_KEY = "your-256-bit-secret-key"; // 256-bit Key
private final int EXPIRATION_TIME = 1000 * 60 * 60 * 10; // 10 Hours
private Key getSigningKey() {
return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
}
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
public String extractUsername(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean isTokenValid(String token, String username) {
return username.equals(extractUsername(token)) && !isTokenExpired(token);
}
private boolean isTokenExpired(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody()
.getExpiration()
.before(new Date());
}
}
Step 3: Custom Authentication Filter তৈরি করা
JWT Token যাচাই করার জন্য একটি Filter তৈরি:
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
String username = null;
String token = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
token = authHeader.substring(7);
username = jwtUtil.extractUsername(token);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtUtil.isTokenValid(token, userDetails.getUsername())) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
Step 4: Spring Security Configuration
JWT Authentication যুক্ত করার জন্য Spring Security কনফিগার করা:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
}
Step 5: Login Controller
লগইন রিকোয়েস্ট থেকে JWT Token জেনারেট করা:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.*;
@RestController
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public String login(@RequestBody AuthRequest authRequest) {
try {
Authentication auth = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword()));
return jwtUtil.generateToken(authRequest.getUsername());
} catch (AuthenticationException e) {
throw new RuntimeException("Invalid username or password");
}
}
}
class AuthRequest {
private String username;
private String password;
// Getters and Setters
}
উপসংহার:
Spring Security-তে JWT Authentication কনফিগার করা একটি শক্তিশালী অথেনটিকেশন প্রক্রিয়া যা Stateless Application-এ ব্যবহৃত হয়।
- Token Generation: লগইনের পর JWT টোকেন তৈরি হয়।
- Token Validation: প্রতিটি রিকোয়েস্টে টোকেন যাচাই করে।
- Security Filter Chain: কাস্টম ফিল্টার ব্যবহার করে টোকেন যাচাই সহজ হয়।
এই কনফিগারেশন অ্যাপ্লিকেশনের নিরাপত্তা নিশ্চিত করে এবং Traditional Session-Based Authentication এর চেয়ে আরও স্কেলেবল।
Read more